﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

using Perseus;
using Perseus.Plugins;

using Hetymine.Executioner.Plugins;

namespace Hetymine.Executioner.Controls {
    public class DisplayPluginComboBox : ComboBox {
        private bool _ItemChanged = false;

        public DisplayPluginComboBox() {
            this.BuildItems();
        }

        private void BuildItems() {
            this.BuildItems(this.SelectedPlugin);
        }
        private void BuildItems(string selected) {            
            ComboBoxItem item;
            string name;
            PluginInstance<IPlugin> plugin;

            this._ItemChanged = true;

            this.Items.Clear();

            // Executioner deafult
            if (this.IncludeExecutionerDefault) {
                item = new ComboBoxItem();

                name = "Executioner Default";
                if (this.DefaultPlugin.Is("@display")) {
                    name += " (default)";
                }

                item.Content = name;
                item.Tag = "@display";
                this.Items.Add(item);

                if (selected.Is("@display")) {
                    this.SelectedIndex = 0;
                }
            }

            // Notepad            
            item = new ComboBoxItem();

            name = "Notepad";
            if (this.DefaultPlugin.IsNot("@display") && Executioner.PluginService != null) {
                plugin = Executioner.PluginService[this.DefaultPlugin, typeof(IDisplay)];

                if (plugin == null) {
                    name += " (default)";
                }
            }

            item.Content = name;
            item.Tag = string.Empty;
            this.Items.Add(item);

            if (Executioner.PluginService != null) {
                plugin = Executioner.PluginService[selected, typeof(IDisplay)];
                if (plugin == null) {
                    this.SelectedIndex = this.Items.Count - 1;
                }
            
                // All other display plugins
                var displayPlugins = from p in Executioner.PluginService.Plugins
                                     where p.Instance is IDisplay
                                     select p;

                foreach (PluginInstance<IPlugin> p in displayPlugins) {
                    item = new ComboBoxItem();

                    name = p.Instance.PluginInfo.Name;
                    if (this.DefaultPlugin == p.Name) {
                        name += " (default)";
                    }

                    item.Content = name;
                    item.Tag = p.Name;
                    this.Items.Add(item);

                    if (selected.Is(p.Name)) {
                        this.SelectedIndex = this.Items.Count - 1;
                    }
                }
            }

            this._ItemChanged = false;
        }

        #region Dependency Properties
        public static readonly DependencyProperty DefaultPluginProperty;
        public static readonly DependencyProperty IncludeExecutionerDefaultProperty;        
        public static readonly DependencyProperty SelectedPluginProperty;

        static DisplayPluginComboBox() {
            DisplayPluginComboBox.DefaultPluginProperty = DependencyProperty.Register(
                "DefaultPlugin",
                typeof(string),
                typeof(DisplayPluginComboBox),
                new FrameworkPropertyMetadata(
                    string.Empty, 
                    FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure,
                    new PropertyChangedCallback(OnDefaultPluginChanged)
                )
            );
            DisplayPluginComboBox.IncludeExecutionerDefaultProperty = DependencyProperty.Register(
                "IncludeExecutionerDefault",
                typeof(bool),
                typeof(DisplayPluginComboBox),
                new FrameworkPropertyMetadata(
                    false,
                    FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure,
                    new PropertyChangedCallback(OnIncludeExecutionerDefaultChanged)
                )
            );
            DisplayPluginComboBox.SelectedPluginProperty = DependencyProperty.Register(
                "SelectedPlugin",
                typeof(string),
                typeof(DisplayPluginComboBox),
                new FrameworkPropertyMetadata(
                    string.Empty,
                    FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure,
                    new PropertyChangedCallback(OnSelectedPluginChanged)
                )
            );


            SelectedIndexProperty.OverrideMetadata(typeof(DisplayPluginComboBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnSelectedIndexChanged)));
        }

        private static void OnDefaultPluginChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
            var c = (DisplayPluginComboBox)o;
            c.BuildItems(c.SelectedPlugin);
        }
        private static void OnIncludeExecutionerDefaultChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
            var c = (DisplayPluginComboBox)o;
            c.BuildItems(c.SelectedPlugin);
        }
        private static void OnSelectedPluginChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
            var c = (DisplayPluginComboBox)o;

            if (c.Items.Count == 0) {
                return;
            }
            
            if (!c._ItemChanged) {
                c._ItemChanged = true;
                
                bool found = false;
                for (int i = 0; i < c.Items.Count; ++i) {                    
                    string selected = ((ComboBoxItem)c.Items[i]).Tag.ToString();
                    if (selected.Is(e.NewValue.ToString())) {
                        c.SelectedIndex = i;
                        found = true;
                        break;
                    }
                }

                if (!found) {
                    // If selected plugin not found, the default executioner plugin 
                    // if included, otherwise notepad                                          
                    c.SelectedIndex = 0;
                }

                c._ItemChanged = false;
            }
        }
        private static void OnSelectedIndexChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
            var c = (DisplayPluginComboBox)o;

            if (c.Items.Count == 0) {
                return;
            }

            if (!c._ItemChanged) {
                c._ItemChanged = true;

                int index = (int)e.NewValue;
                string selected;
                if (index >= 0) {
                    selected = ((ComboBoxItem)c.Items[index]).Tag.ToString();
                }
                else {
                    selected = string.Empty;
                }
                
                c.SelectedPlugin = selected;
                c.BuildItems(selected);

                c._ItemChanged = false;
            }
        }

        public string DefaultPlugin {
            get { return (string)GetValue(DisplayPluginComboBox.DefaultPluginProperty); }
            set { SetValue(DisplayPluginComboBox.DefaultPluginProperty, value); }
        }
        public bool IncludeExecutionerDefault {
            get { return (bool)GetValue(DisplayPluginComboBox.IncludeExecutionerDefaultProperty); }
            set { SetValue(DisplayPluginComboBox.IncludeExecutionerDefaultProperty, value); }
        }
        public string SelectedPlugin {
            get { return (string)GetValue(DisplayPluginComboBox.SelectedPluginProperty); }
            set { SetValue(DisplayPluginComboBox.SelectedPluginProperty, value); }
        }

        #endregion
    }
}
